package com.test.utils;


import lombok.extern.slf4j.Slf4j;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.support.StandardMultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

@Slf4j
public class RequestUtil {
    public final static String HEADER_COMPANY_REQUEST_IP = "HTTP_X_FORWARDED_FOR";
    public final static String HEADER_COMPANY_REQUEST_SERVE_RNAME = "HTTP_SERVER_NAME";
    public final static String HEADER_COMPANY_REQUEST_HTTP_SCHEME_PORT = "HTTP_HTTP_SCHEME_PORT";
    // 多次反向代理后会有多个ip值 的分割符
    private final static String IP_UTILS_FLAG = ",";
    // 未知IP
    private final static String UNKNOWN = "unknown";
    // 本地 IP
    private final static String LOCALHOST_IP = "0:0:0:0:0:0:0:1";
    private final static String LOCALHOST_IP1 = "127.0.0.1";


    public static String getString(HttpServletRequest request, String key) {
        return getString(request, key, "");
    }

    public static String getString(HttpServletRequest request, String key, String defaultValue) {
        String value = request.getParameter(key);
        if (StringUtils.isEmpty(value))
            return defaultValue;
        return value.replace("'", "''").trim();
    }

    public static String[] getStringAry(HttpServletRequest request, String key) {
        return request.getParameterValues(key);
    }

    public static String[] getStringAryByStr(HttpServletRequest request, String key) {
        String value = request.getParameter(key);
        if (StringUtils.isEmpty(value))
            return null;
        String[] aryId = value.split(",");
        String[] lAryId = new String[aryId.length];
        for (int i = 0; i < aryId.length; i++) {
            lAryId[i] = aryId[i];
        }
        return lAryId;
    }

    public static boolean getBoolean(HttpServletRequest request, String key) {
        return getBoolean(request, key, false);
    }

    public static boolean getBoolean(HttpServletRequest request, String key, boolean defaultValue) {
        String value = request.getParameter(key);
        if (StringUtils.isEmpty(value))
            return defaultValue;
        return Boolean.valueOf(value).booleanValue();
    }

    public static int getint(HttpServletRequest request, String key) {
        return getint(request, key, 0);
    }

    public static int getint(HttpServletRequest request, String key, int defaultValue) {
        Integer v = getInteger(request, key, Integer.valueOf(defaultValue));
        return v.intValue();
    }

    public static Integer getInteger(HttpServletRequest request, String key) {
        return getInteger(request, key, 0);
    }

    public static Integer getInteger(HttpServletRequest request, String key, Integer defaultValue) {
        String str = request.getParameter(key);
        if (StringUtils.isEmpty(str))
            return defaultValue;
        return Integer.valueOf(str);
    }

    public static Integer[] getIntAry(HttpServletRequest request, String key) {
        String[] aryKey = request.getParameterValues(key);
        if (aryKey == null)
            return null;
        Integer[] aryInt = new Integer[aryKey.length];
        for (int i = 0; i < aryKey.length; i++) {
            aryInt[i] = Integer.valueOf(Integer.parseInt(aryKey[i]));
        }
        return aryInt;
    }

    public static Integer[] getIntAryByStr(HttpServletRequest request, String key) {
        String value = request.getParameter(key);
        String[] aryId = value.split(",");
        if (aryId == null)
            return null;
        Integer[] iAryId = new Integer[aryId.length];
        for (int i = 0; i < aryId.length; i++) {
            iAryId[i] = Integer.valueOf(aryId[i]);
        }
        return iAryId;
    }

    public static long getlong(HttpServletRequest request, String key) {
        return getlong(request, key, 0L);
    }

    public static long getlong(HttpServletRequest request, String key, long defaultValue) {
        Long v = getLong(request, key, Long.valueOf(defaultValue));
        return v.longValue();
    }

    public static Long getLong(HttpServletRequest request, String key) {
        return getLong(request, key, 0L);
    }

    public static Long getLong(HttpServletRequest request, String key, Long defaultValue) {
        String str = request.getParameter(key);
        if (StringUtils.isEmpty(str))
            return defaultValue;
        return Long.valueOf(str);
    }

    public static Long[] getLongAry(HttpServletRequest request, String key) {
        String[] aryKey = request.getParameterValues(key);
        if (aryKey == null)
            return null;
        Long[] aryLong = new Long[aryKey.length];
        for (int i = 0; i < aryKey.length; i++) {
            aryLong[i] = Long.valueOf(aryKey[i]);
        }
        return aryLong;
    }

    public static Long[] getLongAryByStr(HttpServletRequest request, String key) {
        String value = request.getParameter(key);
        String[] aryId = value.split(",");
        if (aryId == null)
            return null;
        Long[] lAryId = new Long[aryId.length];
        for (int i = 0; i < aryId.length; i++) {
            lAryId[i] = Long.valueOf(aryId[i]);
        }
        return lAryId;
    }

    public static float getfloat(HttpServletRequest request, String key) {
        return getfloat(request, key, 0);
    }

    public static float getfloat(HttpServletRequest request, String key, long defaultValue) {
        Float v = getFloat(request, key, Float.valueOf(defaultValue));
        return v.floatValue();
    }

    public static Float getFloat(HttpServletRequest request, String key) {
        return getFloat(request, key, 0.0F);
    }

    public static Float getFloat(HttpServletRequest request, String key, Float defaultValue) {
        String str = request.getParameter(key);
        if (StringUtils.isEmpty(str))
            return defaultValue;
        return Float.valueOf(str);
    }

    public static Float[] getFloatAry(HttpServletRequest request, String key) {
        String[] aryKey = request.getParameterValues(key);
        if (aryKey == null)
            return null;
        Float[] fAryId = new Float[aryKey.length];
        for (int i = 0; i < aryKey.length; i++) {
            fAryId[i] = Float.valueOf(aryKey[i]);
        }
        return fAryId;
    }

    public static Float[] getFloatAryByStr(HttpServletRequest request, String key) {
        String value = request.getParameter(key);
        String[] aryId = value.split(",");
        if (aryId == null)
            return null;
        Float[] fAryId = new Float[aryId.length];
        for (int i = 0; i < aryId.length; i++) {
            fAryId[i] = Float.valueOf(aryId[i]);
        }
        return fAryId;
    }

    public static double getdouble(HttpServletRequest request, String key) {
        return getdouble(request, key, 0);
    }

    public static double getdouble(HttpServletRequest request, String key, double defaultValue) {
        Double v = getDouble(request, key, Double.valueOf(defaultValue));
        return v.doubleValue();
    }

    public static Double getDouble(HttpServletRequest request, String key) {
        return getDouble(request, key, 0.0D);
    }

    public static Double getDouble(HttpServletRequest request, String key, Double defaultValue) {
        String str = request.getParameter(key);
        if (StringUtils.isEmpty(str))
            return defaultValue;
        return Double.valueOf(str);
    }

    public static Double[] getDoubleAry(HttpServletRequest request, String key) {
        String[] aryKey = request.getParameterValues(key);
        if (aryKey == null)
            return null;
        Double[] dAryId = new Double[aryKey.length];
        for (int i = 0; i < aryKey.length; i++) {
            dAryId[i] = Double.valueOf(aryKey[i]);
        }
        return dAryId;
    }

    public static Double[] getDoubleAryByStr(HttpServletRequest request, String key) {
        String value = request.getParameter(key);
        String[] aryId = value.split(",");
        if (aryId == null)
            return null;
        Double[] dAryId = new Double[aryId.length];
        for (int i = 0; i < aryId.length; i++) {
            dAryId[i] = Double.valueOf(aryId[i]);
        }
        return dAryId;
    }


    public static Map<String, Object> getParameterValueMap(HttpServletRequest request, boolean remainArray) {
        Map<String, Object> map = new HashMap<String, Object>();
        if(request != null) {
            Enumeration<?> params = request.getParameterNames();
            while (params.hasMoreElements()) {
                String key = params.nextElement().toString();
                String[] values = request.getParameterValues(key);
                if (values != null) {
                    if (values.length == 1) {
                        String value = values[0];
                        map.put(key, value);
                    } else {
                        if (remainArray) {
                            map.put(key, values);
                        } else {
                            map.put(key, values != null ? values.toString() : null);
                        }
                    }
                } else {
                    map.put(key, null);
                }
            }
        }
        return map;
    }

    public static Map getParameters(HttpServletRequest request, boolean remainArray) {
        Map map = new HashMap();
        if(request != null) {
            Enumeration<?> params = request.getParameterNames();
            while (params.hasMoreElements()) {
                String key = params.nextElement().toString();
                String[] values = request.getParameterValues(key);
                if (values != null) {
                    if (values.length == 1) {
                        String value = values[0];
                        map.put(key, value);
                    } else {
                        if (remainArray) {
                            map.put(key, values);
                        } else {
                            map.put(key, values != null ? values.toString() : null);
                        }
                    }
                } else {
                    map.put(key, null);
                }
            }
        }
        return map;
    }

    public static Map<String, Object> getHeaderValueMap(HttpServletRequest request) {
        Map<String, Object> map = new HashMap<String, Object>();
        Enumeration<String> headers = request.getHeaderNames();
        while (headers.hasMoreElements()) {
            String name = headers.nextElement();
            map.put(name, request.getHeader(name));
        }
        return map;
    }




    private static String[] getByAry(String[] aryTmp) {
        String[] newAry = new String[aryTmp.length];
        for (int i = 0; i < aryTmp.length; i++) {
            String str = aryTmp[i];
            newAry[i] = str;
        }
        return newAry;
    }

    public static String getStringValues(HttpServletRequest request, String paramName) {
        String[] values = request.getParameterValues(paramName);
        if (values == null || values.length == 0)
            return "";
        String tmp = "";
        for (int i = 0; i < values.length; i++) {
            if (i == 0) {
                tmp = tmp + values[i];
            } else {
                tmp = tmp + "," + values[i];
            }
        }
        return tmp;
    }

    public static Locale getLocal(HttpServletRequest request) {
        Locale local = request.getLocale();
        if (local == null)
            local = Locale.CHINA;
        return local;
    }

    public static Map<String, Object> getRequestHeader(HttpServletRequest request) {
        //request headerNames
        Map<String, Object> headers = new HashMap<>();
        Enumeration<?> enumeration2 = request.getHeaderNames();
        while (enumeration2.hasMoreElements()) {
            String headerName = (String) enumeration2.nextElement();
            headers.put(headerName, request.getHeader(headerName));
        }
        return headers;
    }



    public static final StringBuilder getRequestInfo(HttpServletRequest request) {
        StringBuilder sb = new StringBuilder();
        sb.append("--------------request_params---------\r\n");
        Enumeration<?> enumeration = request.getParameterNames();
        while (enumeration.hasMoreElements()) {
            String paramName = (String) enumeration.nextElement();
            sb.append(paramName + "=" + request.getParameter(paramName) + "\r\n");
        }

        sb.append("-----------request_headerNames---------------\r\n");
        enumeration = request.getHeaderNames();
        while (enumeration.hasMoreElements()) {
            String headerName = (String) enumeration.nextElement();
            sb.append(headerName + "=" + request.getHeader(headerName) + "\r\n");
        }
        return sb;
    }

    /**
     * @param url
     * @param params
     * @param isOverSameParam 相同参数是否覆盖，默认不覆盖
     * @return
     */
    public static String addParametersToUrl(String url, Map<String, Object> params, Boolean isOverSameParam) {
        if (isOverSameParam == null)
            isOverSameParam = false;

        if (url.indexOf("?") == -1) {
            url = url + "?";
        }

        for (Map.Entry<String, Object> entry : params.entrySet()) {
            String paramName = (String) entry.getKey();
            String paramValue = (String) entry.getValue();
            if (!StringUtils.isEmpty(paramValue)) {
                if (isOverSameParam && url.indexOf(paramName) != -1) {
                    String preStr = url.substring(0, url.indexOf(paramName));
                    String tempStr = url.substring(url.indexOf(paramName));
                    String nextStr = "";
                    if (tempStr.indexOf("&") != -1) {
                        nextStr = tempStr.substring(tempStr.indexOf("&"));
                    }
                    url = preStr + paramName + "=" + paramValue + nextStr;
                } else {
                    url += "&" + paramName + "=" + paramValue;
                }
            }
        }
        return url;
    }

    public static String getHttpSchemePort(HttpServletRequest request) {
        StringBuffer url = new StringBuffer();
        String scheme = request.getScheme();
        int port = request.getServerPort();
        if (port < 0)
            port = 80; // Work around java.net.URL bug

        url.append(scheme);
        url.append("://");
        url.append(request.getServerName());
        if ((scheme.equals("http") && (port != 80)) || (scheme.equals("https") && (port != 443))) {
            url.append(':');
            url.append(port);
        }
        return url.toString();
    }



    public static String getFullRequestURL(HttpServletRequest request) {
        StringBuffer url = request.getRequestURL();
        String qString = request.getQueryString();
        if (qString != null) {
            url.append('?');
            url.append(qString);
        }
        return url.toString();
    }

    public static String getFullRequestURI(HttpServletRequest request) {
        StringBuffer url = new StringBuffer(request.getRequestURI());
        String qString = request.getQueryString();
        if (qString != null) {
            url.append('?');
            url.append(qString);
        }
        return url.toString();
    }


    public static String removeCtx(String url, String contextPath) {
        if (url == null)
            return null;
        url = url.trim();
        if (StringUtils.isEmpty(contextPath))
            return url;
        if (StringUtils.isEmpty(url))
            return "";
        if (url.startsWith(contextPath)) {
            url = url.replaceFirst(contextPath, "");
        }
        return url;
    }




    public static String getCloudIp(HttpServletRequest request) {
        if (request == null)
            return null;
        String ip = request.getHeader(HEADER_COMPANY_REQUEST_IP);
        if (StringUtils.isEmpty(ip))
            ip = getIp(request);
        return ip;
    }

    public static String getCloudServerName(HttpServletRequest request) {
        if (request == null)
            return null;
        String serverName = request.getHeader(HEADER_COMPANY_REQUEST_SERVE_RNAME);
        return serverName;
    }

    public static String getCloudHttpSchemePort(HttpServletRequest request) {
        if (request == null)
            return null;
        String httpSchemePort = request.getHeader(HEADER_COMPANY_REQUEST_HTTP_SCHEME_PORT);
        return httpSchemePort;
    }

    /**
     * 访问服务器的客户端ip真实地址
     *
     * @param request
     * @return
     */
    public static String getIp(HttpServletRequest request) {
        if(request == null)
            return null;
        String ip = null;
        try {
            //以下两个获取在k8s中，将真实的客户端IP，放到了x-Original-Forwarded-For。而将WAF的回源地址放到了 x-Forwarded-For了。
            ip = request.getHeader("X-Original-Forwarded-For");
            if (StringUtils.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
                ip = request.getHeader("X-Forwarded-For");
            }
            //获取nginx等代理的ip
            if (StringUtils.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
                ip = request.getHeader("x-forwarded-for");
            }
            if (StringUtils.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
                ip = request.getHeader("Proxy-Client-IP");
            }
            if (StringUtils.isEmpty(ip) || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
                ip = request.getHeader("WL-Proxy-Client-IP");
            }
            if (StringUtils.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_CLIENT_IP");
            }
            if (StringUtils.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_X_FORWARDED_FOR");
            }
            //兼容k8s集群获取ip
            if (StringUtils.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
                ip = request.getRemoteAddr();
                if (LOCALHOST_IP1.equalsIgnoreCase(ip) || LOCALHOST_IP.equalsIgnoreCase(ip)) {
                    //根据网卡取本机配置的IP
                    InetAddress iNet = null;
                    try {
                        iNet = InetAddress.getLocalHost();
                    } catch (UnknownHostException e) {
                        log.error("getClientIp error: ", e);

                    }
                    ip = iNet.getHostAddress();
                }
            }
        } catch (Exception e) {
            log.error("IPUtils ERROR ", e);
        }
        //使用代理，则获取第一个IP地址
        if (!StringUtils.isEmpty(ip) && ip.indexOf(IP_UTILS_FLAG) > 0) {
            ip = ip.substring(0, ip.indexOf(IP_UTILS_FLAG));
        }
        return ip;
    }


    public Map<String, Object> initialRequestFields(HttpServletRequest request) throws Exception {
        StandardMultipartHttpServletRequest _request = (StandardMultipartHttpServletRequest) request;
        //得到基础参数
        Map<String, String[]> paramMap = _request.getParameterMap();
        //得到文件
        MultiValueMap<String, MultipartFile> multiValueMap = _request.getMultiFileMap();
        Map<String, Object> fieldMap = new HashMap<String, Object>();
        fieldMap.put("formFields", paramMap);
        fieldMap.put("fileFields", multiValueMap);
        return fieldMap;
    }

    public static HttpServletRequest getHttpServletRequest() {
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        // 判断如果不是网页调取服务走的http线程，定时器调取调取时线程没有request
        if (servletRequestAttributes != null) {
            return servletRequestAttributes.getRequest();
        } else {
            return null;
        }
    }

    public static void writeHtml(HttpServletResponse response, String str) {
        PrintWriter out = null;
        try {
            response.setHeader("Content-type", "text/html;charset=UTF-8");
            response.setCharacterEncoding("UTF-8");
            out = response.getWriter();
            out.write(str);
            out.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (Exception e) {
                }
            }
        }
    }

    public static void writeJson(HttpServletResponse response, String str){
        PrintWriter out = null;
        try {
            response.setHeader("Content-type", "application/json;charset=UTF-8");
            response.setCharacterEncoding("UTF-8");
            out = response.getWriter();
            out.write(str);
            out.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if(out != null) {
                try{
                    out.close();
                }catch (Exception e){
                }
            }
        }
    }
}
